/****************************************************************************
 *
 *  ALi (Shanghai) Corporation, All Rights Reserved. 2007 Copyright (C)
 *
 *  File: mp_subtitle.c
 *
 *  Description: This file describes subtitle file operations.
 *
 *  History:
 *      Date        	Author      	Version  		Comment
 *      ====        	======      =======  	=======
 *  1.  2009.5.29  Martin_Xia  	0.0.1  		
 *
 ****************************************************************************/

#include <types.h>
#include <retcode.h>
#include <api/libc/printf.h>

#include <api/libc/string.h>
#include <osal/osal.h>
#include <api/libfs2/stat.h>
#include <api/libfs2/dirent.h>
#include <api/libfs2/statvfs.h>
#include <api/libfs2/unistd.h>
#include <api/libfs2/stdio.h>

#include <api/libmp/media_player_api.h>
#include <api/libmp/mp_subtitle_api.h>
#include "mp_subtitle_vobsub.h"
#include "mp_subtitle.h"
#include "mp_subtitle_srt.h"
#include "mp_subtitle_smi.h"
#include "mp_subtitle_ass.h"

static UINT32 mp_lang_type;	//add by mark

static mp_subtitle_string_to_unicode mp_subtitle_callback = NULL;

/**************************Marco  Define***********************************/
//define Marco
#define utf8_to_u_hostendian(str, uni_str, err_flag) \
{\
	err_flag = 0;\
	if ((str[0]&0x80) == 0)\
		*uni_str++ = *str++;\
	else if ((str[1] & 0xC0) != 0x80) {\
		*uni_str++ = 0xfffd;\
		str+=1;\
	} else if ((str[0]&0x20) == 0) {\
		*uni_str++ = ((str[0]&31)<<6) | (str[1]&63);\
		str+=2;\
	} else if ((str[2] & 0xC0) != 0x80) {\
		*uni_str++ = 0xfffd;\
		str+=2;\
	} else if ((str[0]&0x10) == 0) {\
		*uni_str++ = ((str[0]&15)<<12) | ((str[1]&63)<<6) | (str[2]&63);\
		str+=3;\
	} else if ((str[3] & 0xC0) != 0x80) {\
		*uni_str++ = 0xfffd;\
		str+=3;\
	} else {\
		err_flag = 1;\
	}\
}

#define utf8_char_len(c) ((((int)0xE5000000 >> ((c >> 3) & 0x1E)) & 3) + 1)

/**************************Global  Variables***********************************/
//define the Global  Variables
static char mp_subtitle_ext[MP_SUBTITLE_TYPE_NUMBER][4] = {
	{'.' , 'S', 'R', 'T'},
	{'.' , 'I', 'D', 'X'},
	{'.' , 'T', 'X', 'T'},
	{'.' , 'S', 'M', 'I'},
	{'.' , 'A', 'S', 'S'},
	{'.' , 'S', 'S', 'A'}
};

/**************************Static  Function Declare***********************************/
static unsigned long mp_subtitle_unicode_string_length(const unsigned short* string);
static unsigned long mp_subtitle_unicode_string_to_mb(unsigned short* pwStr);
static long mp_subtitle_utf8_to_unicode(const char* src, long* srcLen, unsigned short* dst);
static long mp_subtitle_utf8_string_to_unicode(unsigned char* utf8,unsigned short* Uni_str);
static long mp_subtitle_get_type_by_name(char* name);
static void mp_subtitle_fix_unicode(wchar_t * str,unsigned long * pos);
static void mp_subtitle_fix_utf8(char * str, unsigned long * pos);
static void mp_subtitle_fix(MpSubtitle *subtitle, char * str,unsigned long * pos);
static void mp_subtitle_sort(MpSubtitle *subtitle,char * str,unsigned long * pos,unsigned long * time);
static long mp_subtitle_parse_file(void *handle);
static long  mp_subtitle_get_previous_sub(MpSubtitle *subtitle);
static long mp_subtitle_get_next_sub(MpSubtitle *subtitle);
static long mp_subtitle_get_sub_pos(MpSubtitle *subtitle, unsigned long curtime);
static long mp_subtitle_output_sub(MpSubtitle *subtitle);
static long mp_subtitle_output_sub1(MpSubtitle *subtitle);
static long mp_subtitle_output_image(MpSubtitle *subtitle);
static long mp_subtitle_output_image1(MpSubtitle *subtitle, FILE *file, struct stat *file_status,unsigned char *buffer, MpVobSubMpeg *mpeg, MpVobSubSpu *spu, unsigned long *delay);
static void mp_subtitle_txt_task(unsigned long param1,unsigned long param2);
static void mp_subtitle_image_task(unsigned long param1,unsigned long param2);
static long mp_subtitle_start(MpSubtitle *subtitle);
static void mp_subtitle_stop(MpSubtitle *subtitle);
static void mp_subtitle_pause(MpSubtitle *subtitle, long paused);

//Ben 131127#1 For debug
/*
static UINT32 sub_time_bk;		
void SavCurSubTime(long subtim)
{
	sub_time_bk = subtim;
}

UINT32 GetCurSubTime(void)
{
	return sub_time_bk;
}
*/
//Ben 131127#1
/****************************API  Function ***********************************/
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_create
//
// Description:
//	Create function
//
// Arguments:
//	None
//	
// Return Value:
//	Handle
//
/////////////////////////////////////////////////////////////////////////////
void *mp_subtitle_create(MpSubtitleInitParameter *config)
{
	MpSubtitle			*subtitle;
	
	MP_SUB_DEBUG("====>>mp_subtitle_create()\n");

	if ((!config) || ((!config->get_time) && (!config->get_time_ms)) || (!config->osd_create) || (!config->osd_destroy) || (!config->osd_control))
	{
		MP_SUB_DEBUG("mp_subtitle_create: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_create()\n");
		return NULL;
	}
	

	subtitle = (MpSubtitle*)MALLOC(sizeof(MpSubtitle));
	if (!subtitle)
	{
		MP_SUB_DEBUG("mp_subtitle_create: Malloc Failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_create()\n");
		return NULL;
	}
	

	MEMSET(subtitle, 0, sizeof (MpSubtitle));

	subtitle->current_sub_file_id = -1;
	if ((config->file_buffer) && (config->file_buffer_size >= 1024*350))
	{
		subtitle->file_buffer = (char*)(config->file_buffer);
		subtitle->file_buffer_size_limit = config->file_buffer_size;
		subtitle->file_buffer_assigned = 1;
	}
	else
	{
		subtitle->file_buffer = (char*)MALLOC(1024*350);
		subtitle->file_buffer_size_limit = 1024*350;
	}
	subtitle->position_offset = (unsigned long*)MALLOC(MP_SUBTITLE_MAX_SUB_COUNT*sizeof(long));
	subtitle->position_time = (unsigned long*)MALLOC(MP_SUBTITLE_MAX_SUB_COUNT*sizeof(long));

	
	subtitle->subtitle_osd_functions.osd_create = config->osd_create;
	subtitle->subtitle_osd_functions.osd_destroy= config->osd_destroy;
	subtitle->subtitle_osd_functions.osd_control= config->osd_control;
	if (config->get_time_ms)
	{
		subtitle->get_time = config->get_time_ms;
		subtitle->time_in_ms = 1;
	}
	else
	{
		subtitle->get_time = config->get_time;
	}
	
	MP_SUB_DEBUG("<<====mp_subtitle_create()\n");

	return subtitle;
}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_delete
//
// Description:
//	Delete function
//
// Arguments:
//	Handle
//	
// Return Value:
//	None
//
/////////////////////////////////////////////////////////////////////////////
void mp_subtitle_delete(void *handle)
{
	MpSubtitle			*subtitle;
	
	MP_SUB_DEBUG("====>>mp_subtitle_delete()\n");

	if (!handle)
	{
		MP_SUB_DEBUG("mp_subtitle_delete: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_delete()\n");
		return;
	}

	subtitle = (MpSubtitle*)handle;

	mp_subtitle_stop(subtitle);

	if ((!subtitle->file_buffer_assigned) && (subtitle->file_buffer))
	{
		FREE(subtitle->file_buffer);
	}

	if (subtitle->position_offset)
	{
		FREE(subtitle->position_offset);
	}

	if (subtitle->position_time)
	{
		FREE(subtitle->position_time);
	}
	
	FREE(subtitle);


	MP_SUB_DEBUG("<<====mp_subtitle_delete()\n");

}

/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_auto_load
//
// Description:
//	Auto load a subtitle file
//
// Arguments:
//	Handle
//	Subtitle file name	
//	
// Return Value:
//	  1 - Success
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
//vic100507#1 begin
char* strlwr(char *s)                         
{
	unsigned char AL; 
	register char *DX,*SI; 
	DX=SI=s; 
	while((AL=*SI++)!='\0') 
	{
		AL-='A'; 
		if(AL>'Z'-'A')continue; 
		SI[-1]+='a'-'A'; 
	}   
	return DX; 
}
//vic100507#1 end
#if 1//joey.che
int mp_subtile_get_sub_file_num(void *handle)
{
	MpSubtitle  *subtitle;
	subtitle = (MpSubtitle*)handle;
	if(subtitle)
		return subtitle->avail_file_count;
	else
		return 0;		
}
int mp_subtile_get_cur_sub_id(void *handle)
{
	MpSubtitle  *subtitle;
	subtitle = (MpSubtitle*)handle;
	if(subtitle)
		return subtitle->current_sub_file_id;
	else
		return -1;		
}
long mp_subtitle_change_ext_sub_id(void *handle,char *video_name,int extSubId)
{
#if 0
	MpSubtitle						*subtitle;
	long 	ret;
	MP_SUB_DEBUG("====>>mp_subtitle_change_ext_sub_id()\n");
	if ((!handle))
	{
		MP_SUB_DEBUG("mp_subtitle_change_ext_sub_id: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_change_ext_sub_id()\n");
		return;
	}
	subtitle = (MpSubtitle*)handle;
#if 0	
	mp_subtitle_pause(subtitle, TRUE);
	osal_task_sleep(200);
	subtitle->current_sub_file_id = extSubId;
	mp_subtitle_parse_file(handle);//parse new another external sub file.
	mp_subtitle_pause(subtitle, FALSE);
#else
	mp_subtitle_unload(subtitle);
	subtitle->current_sub_file_id = extSubId;
	ret = mp_subtitle_parse_file(handle);
	if (ret <0)
	{
		MP_SUB_DEBUG("mp_subtitle_change_ext_sub_id: Parse Subtitle Failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_change_ext_sub_id()\n");
		return -1;
	}	
	ret = mp_subtitle_start(subtitle);
	if (ret <0)
	{
		MP_SUB_DEBUG("mp_subtitle_change_ext_sub_id: Start Subtitle Task Failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_change_ext_sub_id()\n");
		return -1;
	}
	MP_SUB_DEBUG("<<====mp_subtitle_change_ext_sub_id()\n");	
#endif
#else
	MpSubtitle						*subtitle;
	char 							*ext;
	char								file_path[FULL_PATH_SIZE];
	long								index;
	long								ret;
	struct stat						file_status;
	
	
	MP_SUB_DEBUG("====>>mp_subtitle_auto_load()\n");

	if ((!handle)||(!video_name))
	{
		MP_SUB_DEBUG("mp_subtitle_auto_load: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");
		return -1;
	}


	subtitle = (MpSubtitle*)handle;
	
	STRCPY(file_path, video_name);
	ext = strrchr(file_path, (long)'.');
	if (!ext)
	{
		MP_SUB_DEBUG("mp_subtitle_auto_load: Wrong Video File Name!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");
		return -1;
	}

	for (index=0; index<MP_SUBTITLE_TYPE_NUMBER; ++index)
	{
		strncpy(ext, (char*)(mp_subtitle_ext+index), 4);
		ret = fs_stat(file_path, &file_status);
		if (ret < 0)
		{
			strlwr(ext);
			ret = fs_stat(file_path, &file_status);
		}
		
		if (ret == 0)
		{
			MP_SUB_DEBUG("mp_subtitle_auto_load:file exist! File name: %s\n", file_path);
			ret = mp_subtitle_get_type_by_name(file_path);
			if (ret != MP_SUBTITLE_TYPE_UNKNOWN)
			{
				subtitle->avail_sub_files[subtitle->avail_file_count].avail_file_type = ret;
				STRCPY(subtitle->avail_sub_files[subtitle->avail_file_count].avail_sub_file, file_path);
				subtitle->avail_file_count++;
			}
			
		}
	
	}

	subtitle->current_sub_file_id = extSubId;
	
	ret = mp_subtitle_parse_file(handle);
	if (ret <0)
	{
		MP_SUB_DEBUG("mp_subtitle_auto_load: Parse Subtitle Failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");
		return -1;
	}
	
	ret = mp_subtitle_start(subtitle);
	if (ret <0)
	{
		MP_SUB_DEBUG("mp_subtitle_auto_load: Start Subtitle Task Failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");
		return -1;
	}


	MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");

	return 1;
#endif
}
#endif

BOOL mp_find_ext_subtitle(char *search_path)
{
 	BOOL find = FALSE;
	UINT8 index =0;
	char *ext;
	UINT8 ext_subt_cnt =0;
	struct stat	file_status;
	long ret = -1;
	MP_SUB_DEBUG("===>find_ext_subtitle\n");
	if(search_path!=NULL)
	{
		ext = strrchr(search_path, (long)'.');
		for (index=0; index<MP_SUBTITLE_TYPE_NUMBER; ++index)
		{
			MEMSET(ext, 0, strlen(ext));
			strncpy(ext, (char*)(mp_subtitle_ext+index), 4);
			ret = fs_stat(search_path, &file_status);
			if (ret < 0)
			{
				strlwr(ext);
				ret = fs_stat(search_path, &file_status);
			}
			if (ret == 0)
			{
			 	find = TRUE;
				break;
			}
		}
	}
	MP_SUB_DEBUG("<====find_ext_subtitle\n");
	return find;
}
long mp_subtitle_auto_load(void *handle, char *video_name)
{
	MpSubtitle						*subtitle;
	char 							*ext;
	char								file_path[FULL_PATH_SIZE];
	long								index;
	long								ret;
	struct stat						file_status;
	UINT16 len=0;
	
	MP_SUB_DEBUG("====>>mp_subtitle_auto_load()\n");

	if ((!handle)||(!video_name))
	{
		MP_SUB_DEBUG("mp_subtitle_auto_load: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");
		return -1;
	}


	subtitle = (MpSubtitle*)handle;
	MEMSET(&file_path[len], 0, FULL_PATH_SIZE - len);
	
	STRCPY(file_path, video_name);
	ext = strrchr(file_path, (long)'.');
	if (!ext)
	{
		MP_SUB_DEBUG("mp_subtitle_auto_load: Wrong Video File Name!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");
		return -1;
	}

	for (index=0; index<MP_SUBTITLE_TYPE_NUMBER; ++index)
	{
		memset(ext, 0, strlen(ext));
		strncpy(ext, (char*)(mp_subtitle_ext+index), 4);
		ret = fs_stat(file_path, &file_status);
		if (ret < 0)
		{
			strlwr(ext);
			ret = fs_stat(file_path, &file_status);
		}
		
		if (ret == 0)
		{
			MP_SUB_DEBUG("mp_subtitle_auto_load:file exist! File name: %s\n", file_path);
			ret = mp_subtitle_get_type_by_name(file_path);
			if (ret != MP_SUBTITLE_TYPE_UNKNOWN)
			{
				subtitle->avail_sub_files[subtitle->avail_file_count].avail_file_type = ret;
				STRCPY(subtitle->avail_sub_files[subtitle->avail_file_count].avail_sub_file, file_path);
				subtitle->avail_file_count++;
			}
			
		}
	
	}

	subtitle->current_sub_file_id = 0;

	ret = mp_subtitle_parse_file(handle);
	if (ret <0)
	{
		MP_SUB_DEBUG("mp_subtitle_auto_load: Parse Subtitle Failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");
		return -1;
	}
	
	ret = mp_subtitle_start(subtitle);
	if (ret <0)
	{
		MP_SUB_DEBUG("mp_subtitle_auto_load: Start Subtitle Task Failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");
		return -1;
	}


	MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");

	return 1;
}


long mp_subtitle_load(void *handle, char *subtitle_name)
{
	MpSubtitle						*subtitle;
	char 							*ext;
	char								file_path[FULL_PATH_SIZE];
	long								index;
	long								ret;
	struct stat						file_status;
	
	
	MP_SUB_DEBUG("====>>mp_subtitle_auto_load()\n");

	if ((!handle)||(!subtitle_name))
	{
		MP_SUB_DEBUG("mp_subtitle_auto_load: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");
		return -1;
	}


	subtitle = (MpSubtitle*)handle;
#if 0	
	STRCPY(file_path, video_name);
	ext = strrchr(file_path, (long)'.');
	if (!ext)
	{
		MP_SUB_DEBUG("mp_subtitle_auto_load: Wrong Video File Name!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");
		return -1;
	}

	for (index=0; index<MP_SUBTITLE_TYPE_NUMBER; ++index)
	{
		strncpy(ext, (char*)(mp_subtitle_ext+index), 4);
		ret = fs_stat(file_path, &file_status);
		if (ret < 0)
		{
			strlwr(ext);
			ret = fs_stat(file_path, &file_status);
		}
		
		if (ret == 0)
		{
			MP_SUB_DEBUG("mp_subtitle_auto_load:file exist! File name: %s\n", file_path);
			ret = mp_subtitle_get_type_by_name(file_path);
			if (ret != MP_SUBTITLE_TYPE_UNKNOWN)
			{
				subtitle->avail_sub_files[subtitle->avail_file_count].avail_file_type = ret;
				STRCPY(subtitle->avail_sub_files[subtitle->avail_file_count].avail_sub_file, file_path);
				subtitle->avail_file_count++;
			}
			
		}
	
	}
#else
 	ret = mp_subtitle_get_type_by_name(subtitle_name);
	if (ret != MP_SUBTITLE_TYPE_UNKNOWN)
	{
		subtitle->avail_sub_files[subtitle->avail_file_count].avail_file_type = ret;
		STRCPY(subtitle->avail_sub_files[subtitle->avail_file_count].avail_sub_file, subtitle_name);
		subtitle->avail_file_count++;
	}
 
#endif
	subtitle->current_sub_file_id = 0;

	ret = mp_subtitle_parse_file(handle);
	if (ret <0)
	{
		MP_SUB_DEBUG("mp_subtitle_auto_load: Parse Subtitle Failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");
		return -1;
	}
	
	ret = mp_subtitle_start(subtitle);
	if (ret <0)
	{
		MP_SUB_DEBUG("mp_subtitle_auto_load: Start Subtitle Task Failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");
		return -1;
	}


	MP_SUB_DEBUG("<<====mp_subtitle_auto_load()\n");

	return 1;
}



/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_unload
//
// Description:
//	Unload a subtitle file
//
// Arguments:
//	Handle
//	
// Return Value:
//	None
//
/////////////////////////////////////////////////////////////////////////////
void mp_subtitle_unload(void *handle)
{
	MpSubtitle						*subtitle;
	
	MP_SUB_DEBUG("====>>mp_subtitle_unload()\n");

	if ((!handle))
	{
		MP_SUB_DEBUG("mp_subtitle_unload: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_unload()\n");
		return;
	}


	subtitle = (MpSubtitle*)handle;

	mp_subtitle_stop(subtitle);

	MP_SUB_DEBUG("<<====mp_subtitle_unload()\n");

}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_hide_sub
//
// Description:
//	Hide subtitle display
//
// Arguments:
//	Handle
//	Hide or Not
//	
// Return Value:
//	None
//
/////////////////////////////////////////////////////////////////////////////
void mp_subtitle_hide_sub(void *handle, long hide)
{
	MpSubtitle						*subtitle;
	
	MP_SUB_DEBUG("====>>mp_subtitle_hide_sub()\n");

	if ((!handle))
	{
		MP_SUB_DEBUG("mp_subtitle_hide_sub: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_hide_sub()\n");
		return;
	}


	subtitle = (MpSubtitle*)handle;
	
	mp_subtitle_pause(subtitle, hide);
	
	MP_SUB_DEBUG("<<====mp_subtitle_hide_sub()\n");

}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_query_language
//
// Description:
//	Query language infomation in subtitle file
//
// Arguments:
//	handle - Handle
//	number - Language Number
//	description - Language description
//	description_len - Length of language description. Should >= 4*number
//	
// Return Value:
//	  1 - Success
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
long mp_subtitle_query_language(void *handle, long *number, long *current_language_index, char* description, long *description_len)
{
	MpSubtitle						*subtitle;
	long								ret;
	
	
	MP_SUB_DEBUG("====>>mp_subtitle_change_language()\n");

	if ((!handle))
	{
		MP_SUB_DEBUG("mp_subtitle_change_language: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_change_language()\n");
		return -1;
	}

	subtitle = (MpSubtitle*)handle;
	ret = -1;
	
	if (subtitle->avail_sub_files[subtitle->current_sub_file_id].avail_file_type == MP_SUBTITLE_TYPE_SUB)
	{
		ret = mp_subtitle_vobsub_query_language(subtitle, &subtitle->vob_sub, number, current_language_index, description, description_len);
	}

	
	MP_SUB_DEBUG("<<====mp_subtitle_change_language()\n");

	return ret;

}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_change_language
//
// Description:
//	Change subtitle language
//
// Arguments:
//	handle - Handle
//	language_index - Language index. Start from 0, not 1.
//	
// Return Value:
//	  1 - Success
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
long mp_subtitle_change_language(void *handle, long language_index)
{
	MpSubtitle						*subtitle;
	long								ret;
	
	
	MP_SUB_DEBUG("====>>mp_subtitle_change_language()\n");

	if ((!handle))
	{
		MP_SUB_DEBUG("mp_subtitle_change_language: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_change_language()\n");
		return -1;
	}

	subtitle = (MpSubtitle*)handle;
	ret = -1;
	
	if (subtitle->avail_sub_files[subtitle->current_sub_file_id].avail_file_type == MP_SUBTITLE_TYPE_SUB)
	{
		mp_subtitle_pause(subtitle, TRUE);
		osal_task_sleep(200);
		ret = mp_subtitle_vobsub_change_language(subtitle, &subtitle->vob_sub, language_index);
		mp_subtitle_pause(subtitle, FALSE);
	}

	
	MP_SUB_DEBUG("<<====mp_subtitle_change_language()\n");

	return ret;
}


/**************************Internal Static  Function ***********************************/
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_unicode_string_length
//
// Description:
//	Borrowed from osd library. 
//
// Arguments:
//	?
//	
// Return Value:
//	0 - Failed
//	other - string length
//
/////////////////////////////////////////////////////////////////////////////
static unsigned long mp_subtitle_unicode_string_length(const unsigned short* string)
{
	unsigned long i=0;

	if(string == NULL)
		return 0;
	
	while (string[i])
		i++;
	return i;
}

/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_unicode_string_to_mb
//
// Description:
//	Borrowed from osd library. 
//
// Arguments:
//	?
//	
// Return Value:
//	0 - Failed
//	other - Success
//
/////////////////////////////////////////////////////////////////////////////
static unsigned long mp_subtitle_unicode_string_to_mb(unsigned short* pwStr)
 {
 	if(pwStr == NULL)
		return 0;
	
 #if(SYS_CPU_ENDIAN==ENDIAN_BIG)
	return mp_subtitle_unicode_string_length(pwStr);
#else
	unsigned long i=0;
	while(pwStr[i])
	{
		pwStr[i]=(unsigned short)(((pwStr[i]&0x00ff)<<8) | ((pwStr[i]&0xff00)>>8));
		i++;
	}
	return i;
#endif
 }

/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_utf8_to_unicode
//
// Description:
//	Borrowed from osd library. 
//
// Arguments:
//	?
//	
// Return Value:
//	0 - Success
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
static long mp_subtitle_utf8_to_unicode(const char* src, long* srcLen, unsigned short* dst)
{
	long srcLimit = *srcLen;
	long srcCount = 0;
	long dstCount = 0;
	long j;

	while (srcCount < srcLimit)
	{
		unsigned short	unicode;
		unsigned short	*UNICODE = &unicode;
		unsigned char	*UTF8 = (unsigned char *)src + srcCount;
		long     err_flag;

		if ((srcCount + utf8_char_len(src[srcCount])) > srcLimit)
			break;

		utf8_to_u_hostendian(UTF8, UNICODE, err_flag);
		if (err_flag == 1)
			return -1;

#if(SYS_CPU_ENDIAN==ENDIAN_LITTLE)
        *dst++ = ((unicode&0x00ff)<<8) | ((unicode&0xff00)>>8);
#else
        *dst++ = unicode;
#endif
		srcCount += UTF8 - ((unsigned char *)(src + srcCount));
	}

	*srcLen = srcCount;

	return 0;
}

/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_utf8_string_to_unicode
//
// Description:
//	Borrowed from osd library. 
//
// Arguments:
//	?
//	
// Return Value:
//	0 - Success
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
static long mp_subtitle_utf8_string_to_unicode(unsigned char* utf8,unsigned short* Uni_str)
{
	long result;
	unsigned long utf8len;


	utf8len = strlen(utf8) + 1;

	result = mp_subtitle_utf8_to_unicode(utf8, (long *) & utf8len,Uni_str);

	return result;
}

/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_get_type_by_name
//
// Description:
//	Get subtitle type
//
// Arguments:
//	Name
//	
// Return Value:
//	>0 - Type
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
static long mp_subtitle_get_type_by_name(char* name)
{
	char 							*ext;
	long								type;
	long								index;

	MP_SUB_DEBUG("====>>mp_subtitle_get_type_by_name()\n");

	if (!name)
	{
		MP_SUB_DEBUG("mp_subtitle_get_type_by_name: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_get_type_by_name()\n");
		return -1;
	}


	type = MP_SUBTITLE_TYPE_UNKNOWN;
	ext = strrchr(name, (long)'.');
	if (ext)
	{
		if (!strncasecmp(ext, ".SRT", 4))
		{
			type = MP_SUBTITLE_TYPE_SRT;
		}
		else if (!strncasecmp(ext, ".IDX", 4))
		{
			type = MP_SUBTITLE_TYPE_SUB;
		}
		else if (!strncasecmp(ext, ".TXT", 4))
		{
			type = MP_SUBTITLE_TYPE_TXT;//MP_SUBTITLE_TYPE_SUB;//cmx0815
		}
		else if (!strncasecmp(ext, ".SMI", 4))
		{
			type = MP_SUBTITLE_TYPE_SMI;
		}
		else if (!strncasecmp(ext, ".ASS", 4))
		{
			type = MP_SUBTITLE_TYPE_ASS;
		}
		else if (!strncasecmp(ext, ".SSA", 4))
		{
			type = MP_SUBTITLE_TYPE_SSA;
		}

	}

	
	MP_SUB_DEBUG("<<====mp_subtitle_get_type_by_name()\n");

	return type;
}

/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_fix_unicode
//
// Description:
//	Remove unnicode file double space
//
// Arguments:
//	str - File buffer
//	pos- offset
//	
// Return Value:
//	None
//
/////////////////////////////////////////////////////////////////////////////
static void mp_subtitle_fix_unicode(wchar_t * str,unsigned long * pos)
{
	wchar_t						*bot;
	wchar_t						*eot;
	
	MP_SUB_DEBUG("====>>mp_subtitle_fix_unicode()\n");

	if ((!str)||(!pos))
	{
		MP_SUB_DEBUG("mp_subtitle_fix_unicode: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_fix_unicode()\n");
		return;
	}

	bot=0;
	eot=0;
	// Step 3 - remove double spaces
	while (*pos!=0xFFFFFFFF)
	{
		bot=str+*pos;
		eot=bot;
		while (1)
		{
			while (*eot==L' ' && (*(eot+1)==L' ' || *(eot+1)==L'\0')) 
			{
				eot++;
			}
			
			*bot=*eot;

			if (*bot==L'\0')
			{
				break;
			}
			
			if (bot!=eot)
			{
				*eot=L' ';
			}
			
			bot++;
			eot++;
		}
		pos++;
	}

	MP_SUB_DEBUG("<<====mp_subtitle_fix_unicode()\n");
	
}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_fix_utf8
//
// Description:
//	Remove utf8 file double space
//
// Arguments:
//	str - File buffer
//	pos- offset
//	
// Return Value:
//	None
//
/////////////////////////////////////////////////////////////////////////////
static void mp_subtitle_fix_utf8(char * str, unsigned long * pos)
{
	char						*bot;
	char						*eot;
	
	MP_SUB_DEBUG("====>>mp_subtitle_fix_utf8()\n");

	if ((!str)||(!pos))
	{
		MP_SUB_DEBUG("mp_subtitle_fix_utf8: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_fix_utf8()\n");
		return;
	}

	bot=0;
	eot=0;
	// Step 3 - remove double spaces
	while (*pos!=0xFFFFFFFF)
	{
		bot=str+*pos;
		eot=bot;
		while (1)
		{
			while (*eot==' ' && (*(eot+1)==' ' || *(eot+1)=='\0')) 
			{
				eot++;
			}
			
			*bot=*eot;

			if (*bot=='\0')
			{
				break;
			}
			
			if (bot!=eot)
			{
				*eot=' ';
			}
			
			bot++;
			eot++;
		}
		pos++;
	}

	MP_SUB_DEBUG("<<====mp_subtitle_fix_utf8()\n");
	
}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_fix
//
// Description:
//	Remove subtitle file double space
//
// Arguments:
//	subtitle - Handle
//	str - File buffer
//	pos - Offset
//	
// Return Value:
//	None
//
/////////////////////////////////////////////////////////////////////////////
static void mp_subtitle_fix(MpSubtitle *subtitle, char * str,unsigned long * pos)
{
	if ((!subtitle)||(!str)||(!pos))
	{
		MP_SUB_DEBUG("mp_subtitle_fix: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_fix()\n");
		return;
	}
	
	if (subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_L_UNICODE)
	{
		mp_subtitle_fix_unicode((wchar_t*)str, pos);
	}
	else if ((subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_UTF8) || (subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_ANSI))
	{
		mp_subtitle_fix_utf8(str, pos);
	}

	MP_SUB_DEBUG("<<====mp_subtitle_fix()\n");

}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_sort
//
// Description:
//	Sort a processed subtitle file to time order
//
// Arguments:
//	subtitle - Handle
//	str - File buffer
//	pos - Offset
//	time - Time code
//
// Return Value:
//	None
//
/////////////////////////////////////////////////////////////////////////////
static void mp_subtitle_sort(MpSubtitle *subtitle,char * str,unsigned long * pos,unsigned long * time)
{
	unsigned long						*pos1;
	unsigned long						*pos2;
	unsigned long						pos3;
	unsigned long						*tim1;
	unsigned long						*tim2;
	unsigned long						tim3;
	unsigned long						counter;	 //Robin 140320

	if ((!subtitle)||(!str)||(!pos)||(!time))
	{
		MP_SUB_DEBUG("mp_subtitle_sort: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_sort()\n");
		return;
	}

	//Robin 140320	-->
	pos1=pos; tim1=time;
	counter = 0;
	while(*pos1!=0xFFFFFFFF)
	{

	    	MP_SUB_DEBUG("counter:%d,pos1:%d,tim1:%d\n",counter,*pos1,*tim1);

		pos2=pos1+1; tim2=tim1+1;
		if(*pos2==0xFFFFFFFF)
			break;

		if((*tim1>*tim2)&&(counter&1))  //just Compare the end of the current and the beginning of the next(1/3/5/7/9 .etc)
		{
			*tim2 = *tim1;
		}
		pos1++;
		tim1++;
		counter++;
	}
	//Robin 140320	<--

	pos1=pos; tim1=time;

	while (*pos1!=0xFFFFFFFF)
	{
		pos2=pos1+1; tim2=tim1+1;
		while (*pos2!=0xFFFFFFFF)
		{
			if (*tim1>*tim2)
			{
				pos3=*pos2;
				tim3=*tim2;
				*pos2=*pos1;
				*tim2=*tim1;
				*pos1=pos3;
				*tim1=tim3;
			}
			pos2++;
			tim2++;
		}
		pos1++;
		tim1++;
	}
/*
	pos1=pos; tim1=time;
	while (*pos1!=0xFFFFFFFF && *(pos1+1)!=0xFFFFFFFF && *(pos1+2)!=0xFFFFFFFF)
	{
		//if (*(str+*(pos1))!='\0' && *(str+*(pos1+1))=='\0' && (*(str+*(pos1+2))=='\0' || subtitle->no_hide))
		{
			*(pos1+1)=*pos1;
			*(tim1+1)=*tim1;
		}
		pos1++;
		tim1++;
	}
*/	

	MP_SUB_DEBUG("<<====mp_subtitle_sort()\n");
}

/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_parse_file
//
// Description:
//	Parse a subtitle file
//
// Arguments:
//	handle - Handle
//	
// Return Value:
//	 1 - Success
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
static long mp_subtitle_parse_file(void *handle)
{
	MpSubtitle						*subtitle;
	FILE								*file;
	char								*filename;
	unsigned long						file_length;
	long								ret;
	unsigned char						txt_header[10];

	
	MP_SUB_DEBUG("====>>mp_subtitle_parse()\n");

	if (!handle)
	{
		MP_SUB_DEBUG("mp_subtitle_parse: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_parse()\n");
		return -1;
	}


	subtitle = (MpSubtitle*)handle;

	if ((subtitle->current_sub_file_id < 0) || (subtitle->avail_file_count > MP_SUBTITLE_TYPE_NUMBER))
	{
		MP_SUB_DEBUG("mp_subtitle_parse: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_parse()\n");
		return -1;
	}

	filename = subtitle->avail_sub_files[subtitle->current_sub_file_id].avail_sub_file;
	file = fopen(filename, "rb");
	if (!file)
	{
		MP_SUB_DEBUG("mp_subtitle_parse: Open file failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_parse()\n");
		return -1;
	}

	fseek(file, 0, SEEK_END);   
	file_length = ftell(file);
	fseek(file, 0, SEEK_SET);


	ret = fread(txt_header, 10, 1, file);
	if (ret != 10)
	{
		MP_SUB_DEBUG("mp_subtitle_parse: fread txt header failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_parse()\n");
		return -1;
	}


	if (txt_header[0]==0xFF && txt_header[1]==0xFE )
	{
		subtitle->txt_file.txt_type = MP_SUBTITLE_TXT_TYPE_L_UNICODE;
		subtitle->txt_file.bom = 2;
	}
	else if (txt_header[0]==0xFE && txt_header[1]==0xFF)
	{
		subtitle->txt_file.txt_type = MP_SUBTITLE_TXT_TYPE_B_UNICODE;
		subtitle->txt_file.bom = 2;
	}
	else if (txt_header[0]==0xEF && txt_header[1]==0xBB && txt_header[2]==0xBF)
	{
		subtitle->txt_file.txt_type = MP_SUBTITLE_TXT_TYPE_UTF8;
		subtitle->txt_file.bom = 3;
	}
	else if (txt_header[0]==0x2B && txt_header[1]==0x2F && txt_header[2]==0x76 && (txt_header[3]==0x38 || txt_header[3]==0x39 || txt_header[3]==0x2B || txt_header[3]==0x2F))
	{
		subtitle->txt_file.txt_type = MP_SUBTITLE_TXT_TYPE_UTF7;
		subtitle->txt_file.bom = 4;
	}
	else
	{
		subtitle->txt_file.txt_type = MP_SUBTITLE_TXT_TYPE_ANSI;
		subtitle->txt_file.bom = 0;
	}


	if (file_length+32> subtitle->file_buffer_size_limit)
	{
		MP_SUB_DEBUG("mp_subtitle_parse: Don't have enough memory!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_parse()\n");
		fclose(file);
		return -1;
	}

	fseek(file, subtitle->txt_file.bom, SEEK_SET);
	file_length = file_length-subtitle->txt_file.bom;
	if(subtitle->file_buffer == NULL)
	{
		MP_SUB_DEBUG("mp_subtitle_parse: subtitle->file_buffer malloc fail!\n");
		return -1;
	}
	ret = fread(subtitle->file_buffer, file_length, 1, file);
	fclose(file);
	if ((ret<0)||((unsigned long)ret != file_length))
	{
		MP_SUB_DEBUG("mp_subtitle_parse: fread file failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_parse()\n");
		return -1;
	}

	subtitle->file_buffer[file_length] = 0;
	subtitle->file_buffer[file_length+1] = 0;

	ret = subtitle->avail_sub_files[subtitle->current_sub_file_id].avail_file_type;
	if (ret == MP_SUBTITLE_TYPE_SRT)
	{
		mp_subtitle_parse_srt(subtitle,  subtitle->file_buffer, subtitle->position_offset, subtitle->position_time);
		mp_subtitle_fix(subtitle, subtitle->file_buffer, subtitle->position_offset);
		mp_subtitle_sort(subtitle, subtitle->file_buffer, subtitle->position_offset, subtitle->position_time);
		//mp_subtitle_output_sub(subtitle);
		
	}
	else if(ret == MP_SUBTITLE_TYPE_TXT)//add for txt special	//cmx0815
	{
		mp_subtitle_parse_txt(subtitle,  subtitle->file_buffer, subtitle->position_offset, subtitle->position_time);
		mp_subtitle_fix(subtitle, subtitle->file_buffer, subtitle->position_offset);
		mp_subtitle_sort(subtitle, subtitle->file_buffer, subtitle->position_offset, subtitle->position_time);
		//mp_subtitle_output_sub(subtitle);		
	}		
	else if (ret == MP_SUBTITLE_TYPE_SUB)
	{
		mp_subtitle_parse_vobsub(subtitle);
		//mp_subtitle_output_image(subtitle);
	}
	else if (ret == MP_SUBTITLE_TYPE_SMI)
	{
		mp_subtitle_parse_smi(subtitle,  subtitle->file_buffer, subtitle->position_offset, subtitle->position_time);
		mp_subtitle_fix(subtitle, subtitle->file_buffer, subtitle->position_offset);
		mp_subtitle_sort(subtitle, subtitle->file_buffer, subtitle->position_offset, subtitle->position_time);
		//mp_subtitle_output_sub(subtitle);
	}	
	else if ((ret == MP_SUBTITLE_TYPE_ASS) || (ret == MP_SUBTITLE_TYPE_SSA))
	{
		mp_subtitle_parse_ass(subtitle,  subtitle->file_buffer, subtitle->position_offset, subtitle->position_time);
		mp_subtitle_fix(subtitle, subtitle->file_buffer, subtitle->position_offset);
		mp_subtitle_sort(subtitle, subtitle->file_buffer, subtitle->position_offset, subtitle->position_time);
		//mp_subtitle_output_sub(subtitle);
	}		
	else
	{
		MP_SUB_DEBUG("mp_subtitle_parse: We don't support this type now!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_parse()\n");
		return -1;
	}


	MP_SUB_DEBUG("<<====mp_subtitle_parse()\n");
	
	return 1;
}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_get_previous_sub
//
// Description:
//	Get previous subtitle
//
// Arguments:
//	subtitle - handle
//	
// Return Value:
//	 time - Previous subtitle time
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
static long  mp_subtitle_get_previous_sub(MpSubtitle *subtitle)
{
	long							index;
	long long						real_time;
	char							str;
	unsigned short				uni_str;


	MP_SUB_DEBUG("====>>mp_subtitle_get_previous_sub()\n");

	if (!subtitle)
	{
		MP_SUB_DEBUG("mp_subtitle_get_previous_sub: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_get_previous_sub()\n");
		return -1;
	}
	
	index=subtitle->current_pos;
	index--;
	while (index>=0 && index<subtitle->total_sub_count-1)
	{
		str = *(subtitle->file_buffer+subtitle->position_offset[index]);
		uni_str = *((unsigned short*)(subtitle->file_buffer+subtitle->position_offset[index]));
		if ((subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_B_UNICODE) || (subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_L_UNICODE))
		{
			if (uni_str == L'0')
			{
				index--;
				continue;
			}
			else
			{
				break;
			}
			
		}
		else
		{
			if (str == '\0')
			{
				index--;
				continue;
			}
			else
			{
				break;
			}
		}
	}
	
	if (index<0 ||index>subtitle->total_sub_count-1)
	{
		MP_SUB_DEBUG("mp_subtitle_get_previous_sub: Can't find previous subtitle!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_get_previous_sub()\n");		
		return -1;
	}
	
	//real_time=subtitle->speed;
	real_time = 1;
	real_time*=TICKSPERSEC;
	real_time/=-10;
	real_time+=subtitle->position_time[index];

	MP_SUB_DEBUG("<<====mp_subtitle_get_previous_sub()\n");
	
	return (long)real_time;
}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_get_next_sub
//
// Description:
//	Get next subtitle
//
// Arguments:
//	subtitle - handle
//	
// Return Value:
//	 time - Next subtitle time
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////

static long mp_subtitle_get_next_sub(MpSubtitle *subtitle)
{
	long							index;
	long long						real_time;
	char							str;
	unsigned short				uni_str;

	MP_SUB_DEBUG("====>>mp_subtitle_get_next_sub()\n");

	if (!subtitle)
	{
		MP_SUB_DEBUG("mp_subtitle_get_next_sub: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_get_next_sub()\n");
		return -1;
	}
	
	index=subtitle->current_pos;
	index++;
	while (index>=0 && index<subtitle->total_sub_count-1)
	{
		str = *(subtitle->file_buffer+subtitle->position_offset[index]);
		uni_str = *((unsigned short*)(subtitle->file_buffer+subtitle->position_offset[index]));
		if ((subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_B_UNICODE) || (subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_L_UNICODE))
		{
			if (uni_str == L'0')
			{
				index--;
				continue;
			}
			else
			{
				break;
			}
			
		}
		else
		{
			if (str == '\0')
			{
				index--;
				continue;
			}
			else
			{
				break;
			}
		}
	}
	
	if (index<0 ||index>subtitle->total_sub_count-1)
	{
		MP_SUB_DEBUG("mp_subtitle_get_next_sub: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_get_next_sub()\n");		
		return -1;
	}
	
	//real_time=subtitle->Speed;
	real_time = 1;
	real_time*=TICKSPERSEC;
	real_time/=-10;
	real_time+=subtitle->position_time[index];

	MP_SUB_DEBUG("<<====mp_subtitle_get_next_sub()\n");
	
	return (long)real_time;
}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_get_sub
//
// Description:
//	Get a subtitle related to input time
//
// Arguments:
//	subtitle - Handle
//	curtime - Time
//	
// Return Value:
//	 time - Subtitle time
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
/*
static long mp_subtitle_get_sub_pos(MpSubtitle *subtitle, unsigned long curtime)
{	
	unsigned long time,prevtime;
	long long real_time;
	long pos = subtitle->current_pos;
	long k;

	MP_SUB_DEBUG("====>>mp_subtitle_get_sub_pos()\n");

	if (!subtitle)
	{
		MP_SUB_DEBUG("mp_subtitle_get_sub_pos: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_get_sub_pos()\n");
		return -1;
	}
	
	if (curtime==0xffffffff)
	{
		MP_SUB_DEBUG("mp_subtitle_get_sub_pos: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_get_sub_pos()\n");
		return pos;
	}

	//realtime=subtitle->Speed;
	real_time = 1;
	real_time*=TICKSPERSEC;
	real_time/=10;
	real_time+=curtime;
	curtime=(unsigned long)real_time;
	if (subtitle->position_time == NULL || subtitle->total_sub_count==0 || curtime<subtitle->position_time[0] || curtime>subtitle->position_time[subtitle->total_sub_count-2])
	{
		if (subtitle->current_pos!=-1)
		{
			//subtitle->DrawPos = -1;
			//subtitle->SubHeight = 0;
		}
		subtitle->current_pos=-1;
		MP_SUB_DEBUG("mp_subtitle_get_sub_pos: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_get_sub_pos()\n");		
		return pos;
	}

	if (pos<0 || pos>subtitle->total_sub_count-1)
	{
		pos = 0;
	}

	
	for (k=0;k<100;k++)
	{
		if (pos<0 || pos>subtitle->total_sub_count-1)
		{
			pos = 0;	
		}
		
		time	= subtitle->position_time[pos+1];
		prevtime= subtitle->position_time[pos];
		if (pos>subtitle->total_sub_count-1)
		{
			break;
		}
		if (curtime > time)
		{
			pos++;
		}
		else if (curtime < prevtime)
		{
			pos--;
		}
		else
		{
			break;
		}
	}
	
	if(k >= 100)
	{
		//subtitle->DrawPos = pos;
		//subtitle->SubHeight = 0;
	}
	
	if (pos<0 || pos>subtitle->total_sub_count-1)
	{
		pos = 0;
	}
	
	//while (pos>1 && subtitle->PositionTime[pos-1]==subtitle->PositionTime[pos]) pos--;
	subtitle->current_pos=pos;


	MP_SUB_DEBUG("<<====mp_subtitle_get_sub_pos()\n");

	return pos;
}
*/
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_get_sub
//
// Description:
//	Get a subtitle related to input time
//
// Arguments:
//	subtitle - Handle
//	curtime - Time
//	
// Return Value:
//	 time - Subtitle time
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
static long mp_subtitle_get_sub(MpSubtitle *subtitle, unsigned long curtime)
{	
	unsigned long time,prevtime;
	long long real_time;
	long pos;
	long k;

	MP_SUB_DEBUG("====>>mp_subtitle_get_sub_pos()\n");

	if (!subtitle)
	{
		MP_SUB_DEBUG("mp_subtitle_get_sub_pos: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_get_sub_pos()\n");
		return -1;
	}
	
	if (curtime==0xffffffff)
	{
		MP_SUB_DEBUG("mp_subtitle_get_sub_pos: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_get_sub_pos()\n");
		return -1;
	}

	pos = subtitle->current_pos;

	//realtime=subtitle->speed;
	real_time = 1;
	real_time*=TICKSPERSEC;
	real_time/=10;
	real_time+=curtime;
	curtime=(unsigned long)real_time;
	if (subtitle->position_time == NULL || subtitle->total_sub_count==0 || curtime>subtitle->position_time[subtitle->total_sub_count-2])
	{
		subtitle->current_pos=-1;
		MP_SUB_DEBUG("mp_subtitle_get_sub_pos: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_get_sub_pos()\n");		
		return -1;
	}

	if (pos<0 || pos>subtitle->total_sub_count-1)
	{
		pos = 0;
	}

	for (k=0;k<subtitle->total_sub_count;k++)
	{
		if (pos<0 || pos>subtitle->total_sub_count-1)
		{
			pos = 0;	
		}
		
		time	= subtitle->position_time[pos+1];
		prevtime= subtitle->position_time[pos];
		if (subtitle->time_in_ms)
		{
			time /= 100;
			time *= 100;
			prevtime /= 100;
			prevtime *= 100;
		}
		else
		{
			time /= 1000;
			time *= 1000;
			prevtime /= 1000;
			prevtime *= 1000;
		}
		if (pos>subtitle->total_sub_count-1)
		{
			break;
		}
		if (curtime > time)
		{
			pos++;
		}
		else if (curtime < prevtime)
		{
			pos--;
		}
		else
		{
			pos++;
			break;
		}
	}
	
	
	if (pos<0 || pos>subtitle->total_sub_count-1)
	{
		pos = 0;
	}
	else
	{
		subtitle->current_pos=pos;
	}

	MP_SUB_DEBUG("<<====mp_subtitle_get_sub_pos()\n");

	return subtitle->position_time[pos];
}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_output_sub
//
// Description:
//	Output a txt subtitle, for debug
//
// Arguments:
//	subtitle - Handle
//	
// Return Value:
//	 1 - Sucess
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
static long mp_subtitle_output_sub(MpSubtitle *subtitle)
{
	long									ret;
	long									index;
	unsigned long							offset;
	char									*string;
	unsigned short						uni_string[1024];
	MpSubtitleDrawStringParameters			para;
	
	MP_SUB_DEBUG("====>>mp_subtitle_output_sub()\n");

	if (!subtitle)
	{
		MP_SUB_DEBUG("mp_subtitle_output_sub: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_sub()\n");
		return -1;
	}

	index = subtitle->current_pos;
	if (index<0 || index>subtitle->total_sub_count-1)
	{
		index=0;
	}

	subtitle->current_pos = index;

	ret = subtitle->subtitle_osd_functions.osd_create(&subtitle->subtitle_osd);
	if (ret < 0)
	{
		MP_SUB_DEBUG("mp_subtitle_output_sub: Create osd failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_sub()\n");
		return -1;
	}

	while (index<subtitle->total_sub_count-1)
	{
		offset = subtitle->position_offset[index];
		if (offset)
		{
			if (subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_L_UNICODE)
			{
				string= subtitle->file_buffer+offset*2;
				//libc_printf("%s \n", string);
				para.subtitle_osd = subtitle->subtitle_osd;
				para.x = 14;
				para.y = 20;
				para.fg_color = 7;
				para.string = (unsigned short *)string;
				subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_DRAW_STRING, (long)(&para));
			}
			else if ((subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_UTF8) || (subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_ANSI))
			{
				string= subtitle->file_buffer+offset;
				//libc_printf("%s \n", string);				
				mp_subtitle_utf8_string_to_unicode(string, uni_string);
				mp_subtitle_unicode_string_to_mb(uni_string);
				para.subtitle_osd = subtitle->subtitle_osd;
				para.x = 14;
				para.y = 20;
				para.fg_color = 7;
				para.string = (unsigned short *)(&uni_string[0]);
				subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_DRAW_STRING, (long)(&para));
			}

			osal_task_sleep(2000);
			subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_CONTROL_CLEAN_SCREEN, 0);

		}
		index++;
	}


	ret = subtitle->subtitle_osd_functions.osd_destroy(subtitle->subtitle_osd);
	if (ret < 0)
	{
		MP_SUB_DEBUG("mp_subtitle_output_sub: Desaory osd failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_sub()\n");
		return -1;
	}

	
	osal_task_sleep(10000);

	MP_SUB_DEBUG("<<====mp_subtitle_output_sub()\n");
	return 1;
}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_output_sub1
//
// Description:
//	Output a txt subtitle
//
// Arguments:
//	subtitle - Handle
//	
// Return Value:
//	 1 - Sucess
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
static long mp_subtitle_output_sub1(MpSubtitle *subtitle)
{
	long									index;
	unsigned long							offset;
	char									*string;
	unsigned short						uni_string[1024];
	MpSubtitleDrawStringParameters			para;
	
	MP_SUB_DEBUG("====>>mp_subtitle_output_sub1()\n");

	if (!subtitle)
	{
		MP_SUB_DEBUG("mp_subtitle_output_sub: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_sub1()\n");
		return -1;
	}

	subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_CONTROL_CLEAN_SCREEN, 0);

	index = subtitle->current_pos;
	if (index<0 || index>subtitle->total_sub_count-1)
	{
		index=0;
	}

	subtitle->current_pos = index;

	
	offset = subtitle->position_offset[index];
	if (offset)
	{
		if (subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_L_UNICODE)
		{
			string= subtitle->file_buffer+offset*2;
			//libc_printf("%s \n", string);
			para.subtitle_osd = subtitle->subtitle_osd;
			para.x = 14;
			para.y = 20;
			para.fg_color = 7;
			para.string = (unsigned short *)string;
			subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_DRAW_STRING, (long)(&para));
		}
		else if ((subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_UTF8) || (subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_ANSI))
		{
			string= subtitle->file_buffer+offset;
			//libc_printf("%s \n", string);			
            //if(mp_subtitle_callback == NULL)//cmx0801				
            if(subtitle->txt_file.txt_type == MP_SUBTITLE_TXT_TYPE_UTF8)//cmx0801				
			mp_subtitle_utf8_string_to_unicode(string, uni_string);
            else {
                    unsigned long utf8len;
			        utf8len = strlen(string) + 1;
                    mp_subtitle_callback(string, utf8len, uni_string, 100, mp_lang_type);
                }
			mp_subtitle_unicode_string_to_mb(uni_string);
			para.subtitle_osd = subtitle->subtitle_osd;
			para.x = 14;
			para.y = 20;
			para.fg_color = 7;
			para.string = (unsigned short *)(&uni_string[0]);
			subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_DRAW_STRING, (long)(&para));
		}
		
	}

	
	MP_SUB_DEBUG("<<====mp_subtitle_output_sub1()\n");
	return 1;
}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_output_image
//
// Description:
//	Output a image subtitle, for debug
//
// Arguments:
//	subtitle - Handle
//	
// Return Value:
//	 1 - Sucess
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
static long mp_subtitle_output_image(MpSubtitle *subtitle)
{
	long									index;
	unsigned long							offset;
	unsigned long							offset2;	
	char									*filename;
	FILE									*file;
	char									file_path[FULL_PATH_SIZE+100];
	struct stat							file_status;
	char 								*ext;
	long									ret;
	MpVobSubMpeg						mpeg;
	char									spu_fragment[2048];
	MpVobSubSpu							*spu;
	long									spu_length;
	long									seek_address;
	long									aid;
	MpSubtitleDrawImageParameters			para;
	
	
	MP_SUB_DEBUG("====>>mp_subtitle_output_image()\n");

	if (!subtitle)
	{
		MP_SUB_DEBUG("mp_subtitle_output_image: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
		return -1;
	}

	index = subtitle->current_pos;
	if (index<0 || index>subtitle->total_sub_count-1)
	{
		index=0;
	}

	subtitle->current_pos = index;


	filename = subtitle->avail_sub_files[subtitle->current_sub_file_id].avail_sub_file;
	STRCPY(file_path, filename);
	ext = strrchr(file_path, (long)'.');
	if (!ext)
	{
		MP_SUB_DEBUG("mp_subtitle_output_image: Wrong Video File Name!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
		return -1;
	}

	strncpy(ext, ".SUB", 4);
	ret = fs_stat(file_path, &file_status);
	if (ret < 0)
	{
		strlwr(ext);
		ret = fs_stat(file_path, &file_status);
	}
	
	if (ret < 0)
	{
		MP_SUB_DEBUG("mp_subtitle_output_image: Sub File is not existed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
		return -1;
	}


	
	file = fopen(file_path, "rb");
	if (!file)
	{
		MP_SUB_DEBUG("mp_subtitle_output_image: Open file failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
		return -1;
	}

	spu = (MpVobSubSpu*)MALLOC(sizeof(MpVobSubSpu));
	MEMSET(spu, 0, sizeof(MpVobSubSpu));
	mpeg.packet_reserve = 2048;
	mpeg.packet = spu_fragment;

	ret = subtitle->subtitle_osd_functions.osd_create(&subtitle->subtitle_osd);
	if (ret < 0)
	{
		MP_SUB_DEBUG("mp_subtitle_output_image: Create osd failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
		return -1;
	}
	
	subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_CHANGE_PALLETE, (long)subtitle->vob_sub.palette);

	while (index<subtitle->total_sub_count-1)
	{
		offset = subtitle->position_offset[index];
		if (index == subtitle->total_sub_count-2)
		{
			offset2 = file_status.st_size;
		}
		else
		{
			offset2 = subtitle->position_offset[index+1];
		}
		
		//libc_printf("mp_subtitle_output_image: sub file pos = 0x%X \n", offset);
		if (offset == 0x49000)
		{
			SDBBP();
		}

		ret = fseek(file, offset, SEEK_SET);
		if (ret < 0)
		{
			subtitle->subtitle_osd_functions.osd_destroy(subtitle->subtitle_osd);
			FREE(spu);
			fclose(file);
			MP_SUB_DEBUG("mp_subtitle_output_image: Seek file failed!\n");
			MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
			return -1;
		}

		ret = fread(file_path, 2148, 1, file);
		if (ret < 0)
		{
			subtitle->subtitle_osd_functions.osd_destroy(subtitle->subtitle_osd);
			FREE(spu);
			fclose(file);
			MP_SUB_DEBUG("mp_subtitle_output_image: Seek file failed!\n");
			MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
			return -1;
		}

		ret = mp_subtitle_vobsub_parse_ps_packet(file_path, ret, &mpeg);
		seek_address = ret;
		if (ret < 0)
		{
			subtitle->subtitle_osd_functions.osd_destroy(subtitle->subtitle_osd);
			FREE(spu);
			fclose(file);
			//libc_printf("mp_subtitle_output_image: Parse PS packet failed!\n");
			MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
			return -1;
		}
		aid = mpeg.aid;


		for (;(offset+seek_address)<offset2;)
		{
			ret = mp_subtitle_vobsub_spu_reassemble(spu, &mpeg);
			if (ret < 0)
			{
				subtitle->subtitle_osd_functions.osd_destroy(subtitle->subtitle_osd);
				FREE(spu);
				fclose(file);
				//libc_printf("mp_subtitle_output_image: Parse SPU DCCMD failed!\n");
				MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
				return -1;
			}

			if (ret == 2)
			{
				//libc_printf("mp_subtitle_output_image: process one spu packet successed! \n");
				break;
			}

			ret = fseek(file, offset+seek_address, SEEK_SET);
			if (ret < 0)
			{
				subtitle->subtitle_osd_functions.osd_destroy(subtitle->subtitle_osd);
				FREE(spu);
				fclose(file);
				MP_SUB_DEBUG("mp_subtitle_output_image: Seek file failed!\n");
				MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
				return -1;
			}

			ret = fread(file_path, 2148, 1, file);
			if (ret < 0)
			{
				subtitle->subtitle_osd_functions.osd_destroy(subtitle->subtitle_osd);
				FREE(spu);
				fclose(file);
				MP_SUB_DEBUG("mp_subtitle_output_image: Seek file failed!\n");
				MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
				return -1;
			}

			ret = mp_subtitle_vobsub_parse_ps_packet(file_path, ret, &mpeg);
			seek_address += ret;
			if (ret < 0)
			{
				subtitle->subtitle_osd_functions.osd_destroy(subtitle->subtitle_osd);
				FREE(spu);
				fclose(file);
				//libc_printf("mp_subtitle_output_image: Parse PS packet failed!\n");
				MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
				return -1;
			}

			if (aid != mpeg.aid)
			{
				mpeg.packet_size = 0;
			}

		}
		

		ret = mp_subtitle_vobsub_spu_parse_pxd(&subtitle->vob_sub, spu);
		if (ret < 0)
		{
			subtitle->subtitle_osd_functions.osd_destroy(subtitle->subtitle_osd);
			FREE(spu);
			fclose(file);
			//libc_printf("mp_subtitle_output_image: Parse SPU PXD failed!\n");
			MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
			return -1;
		}


		para.subtitle_osd = subtitle->subtitle_osd;
		para.x = spu->start_col;
		para.y = spu->start_row;
		para.width = spu->stride;
		para.height = spu->height;
		para.image = spu->image;
		subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_DRAW_IMAGE, (long)(&para));

		subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_CONTROL_CLEAN_SCREEN, 0);
			
		index++;
	}


	ret = subtitle->subtitle_osd_functions.osd_destroy(subtitle->subtitle_osd);
	if (ret < 0)
	{
		MP_SUB_DEBUG("mp_subtitle_output_image: Desaory osd failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
		return -1;
	}
	
	FREE(spu);
	fclose(file);
	osal_task_sleep(10000);

	MP_SUB_DEBUG("<<====mp_subtitle_output_image()\n");
	return 1;
}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_output_image1
//
// Description:
//	Output a image subtitle
//
// Arguments:
//	subtitle - Handle
//	file - File handle
//	file_status - File status
//	buffer - Cache buffer
//	mpeg - Pointer to ps infomation struct
//	spu -  Pointer to spu infomation struct
//	delay - How many ms this subtitle last 
//	
// Return Value:
//	 1 - Sucess
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
static long mp_subtitle_output_image1(MpSubtitle *subtitle, FILE *file, struct stat *file_status,unsigned char *buffer, MpVobSubMpeg *mpeg, MpVobSubSpu *spu, unsigned long *delay)
{
	long									ret;
	long									index;
	unsigned long							offset;
	unsigned long							offset2;
	unsigned long							time_delay;
	unsigned long							pts_delay;
	long									seek_address;
	long									aid;
	MpSubtitleDrawImageParameters			para;
	
	
	MP_SUB_DEBUG("====>>mp_subtitle_output_image1()\n");

	if ((!subtitle) || (!file) || (!file_status) || (!buffer) || (!mpeg) || (!spu))
	{
		MP_SUB_DEBUG("mp_subtitle_output_image1: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_image1()\n");
		return -1;
	}

	subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_CONTROL_CLEAN_SCREEN, 0);

	index = subtitle->current_pos;
	offset = subtitle->position_offset[index];
	if (index == subtitle->total_sub_count-2)
	{
		offset2 = file_status->st_size;
		time_delay = 0xffffffff;
	}
	else
	{
		offset2 = subtitle->position_offset[index+1];
		if (subtitle->position_time[index+1] > subtitle->position_time[index])
		{
			time_delay = subtitle->position_time[index+1] - subtitle->position_time[index];
		}
		else
		{
			time_delay = subtitle->position_time[index] - subtitle->position_time[index+1];
		}
	}
	
	//libc_printf("mp_subtitle_output_image1: sub file pos = 0x%X \n", offset);
	if (offset == 0x49000)
	{
		//SDBBP();
	}

	ret = fseek(file, offset, SEEK_SET);
	if (ret < 0)
	{
		MP_SUB_DEBUG("mp_subtitle_output_image1: Seek file failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_image1()\n");
		return -1;
	}

	ret = fread(buffer, 2148, 1, file);
	if (ret < 0)
	{
		MP_SUB_DEBUG("mp_subtitle_output_image1: Seek file failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_image1()\n");
		return -1;
	}

	ret = mp_subtitle_vobsub_parse_ps_packet(buffer, ret, mpeg);
	seek_address = ret;
	if (ret < 0)
	{
		//libc_printf("mp_subtitle_output_image1: Parse PS packet failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_image1()\n");
		return -1;
	}
	aid = mpeg->aid;


	for (;(offset+seek_address)<offset2;)
	{
		ret = mp_subtitle_vobsub_spu_reassemble(spu, mpeg);
		if (ret < 0)
		{
			//libc_printf("mp_subtitle_output_image1: Parse SPU DCCMD failed!\n");
			MP_SUB_DEBUG("<<====mp_subtitle_output_image1()\n");
			return -1;
		}

		if (ret == 2)
		{
			//libc_printf("mp_subtitle_output_image1: process one spu packet successed! \n");
			break;
		}

		ret = fseek(file, offset+seek_address, SEEK_SET);
		if (ret < 0)
		{
			MP_SUB_DEBUG("mp_subtitle_output_image1: Seek file failed!\n");
			MP_SUB_DEBUG("<<====mp_subtitle_output_image1()\n");
			return -1;
		}

		ret = fread(buffer, 2148, 1, file);
		if (ret < 0)
		{
			MP_SUB_DEBUG("mp_subtitle_output_image1: Seek file failed!\n");
			MP_SUB_DEBUG("<<====mp_subtitle_output_image1()\n");
			return -1;
		}

		ret = mp_subtitle_vobsub_parse_ps_packet(buffer, ret, mpeg);
		seek_address += ret;
		if (ret < 0)
		{
			//libc_printf("mp_subtitle_output_image1: Parse PS packet failed!\n");
			MP_SUB_DEBUG("<<====mp_subtitle_output_image1()\n");
			return -1;
		}

		if (aid != mpeg->aid)
		{
			mpeg->packet_size = 0;
		}

	}
	

	ret = mp_subtitle_vobsub_spu_parse_pxd(&subtitle->vob_sub, spu);
	if (ret < 0)
	{
		//libc_printf("mp_subtitle_output_image1: Parse SPU PXD failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_output_image1()\n");
		return -1;
	}


	para.subtitle_osd = subtitle->subtitle_osd;
	para.x = spu->start_col;
	para.y = spu->start_row;
	para.width = spu->stride;
	para.height = spu->height;
	para.image = spu->image;
	subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_DRAW_IMAGE, (long)(&para));

	if (spu->end_pts >= spu->start_pts)
	{
		pts_delay = spu->end_pts - spu->start_pts;
	}
	else
	{
		pts_delay = spu->start_pts - spu->end_pts;
	}

	pts_delay /= 9;
	if (pts_delay>5000)
	{
		pts_delay = 5000;
	}

	if (pts_delay > time_delay)
	{
		pts_delay = time_delay;
	}

	*delay = pts_delay;

	MP_SUB_DEBUG("<<====mp_subtitle_output_image1()\n");
	return 1;
}


/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_txt_task
//
// Description:
//	The task for output txt subtitle. It will auto sync with current playing video
//
// Arguments:
//	param1 - Subtitle Handle
//	param2 - Not in use	
//
// Return Value:
//	None
//
/////////////////////////////////////////////////////////////////////////////
static void mp_subtitle_txt_task(unsigned long param1,unsigned long param2)
{
	long								time;
	long								sub_time;
	MpSubtitle						*subtitle;
	long								displayed;
	long								ret;
	//long 							last_sub_time=0;	//Ben 121203#1
	
	
	MP_SUB_DEBUG("====>>mp_subtitle_task()\n");


	subtitle = (MpSubtitle*)param1;
	sub_time = 0;
	displayed = 0;

	
	ret = subtitle->subtitle_osd_functions.osd_create(&subtitle->subtitle_osd);
	if (ret < 0)
	{
		osal_flag_set(subtitle->sub_task_control.parameter.flag_id, MP_SUBTITLE_FLAG_UNSUCCESSFUL);
		MP_SUB_DEBUG("<<====mp_subtitle_task()\n");	
		return;
	}
	else
	{
		osal_flag_set(subtitle->sub_task_control.parameter.flag_id, MP_SUBTITLE_FLAG_SUCCESS);
	}

	while(subtitle->sub_task_control.command != MP_SUBTITLE_TASK_COMMAND_STOP)
	{
		
		if (subtitle->sub_task_control.command == MP_SUBTITLE_TASK_COMMAND_NONE)
		{
			time = subtitle->get_time();
			if (subtitle->time_in_ms)
			{
				time /= 100;
			}

			if (time <= 0)
			{
				//cmx0815 start				
				//osal_task_sleep(10);
				//continue;
				//cmx0815 end
			}

			if (sub_time == 0)
			{
				if (subtitle->time_in_ms)
				{
					sub_time = mp_subtitle_get_sub(subtitle, time*100);
					sub_time /= 100;
				}
				else
				{
					sub_time = mp_subtitle_get_sub(subtitle, time*1000);
					sub_time /= 1000;
				}
			}	

			if (sub_time < 0)
			{
				osal_task_sleep(10);
				continue;
			}


			if (time == sub_time)
			{
				//Ben 121203#1
				#if 0
				MP_SUB_DEBUG("sub_time=%d last_sub_time=%d\n",sub_time,last_sub_time);		
				if(sub_time == last_sub_time)
				{
					sub_time = 0;
					continue;
				}
				last_sub_time = sub_time;
				#endif
				//Ben 121203#1 
				
				//SavCurSubTime(sub_time);	//Ben 131127#1 Just for debug
				sub_time = 0;
				mp_subtitle_output_sub1(subtitle);

			}
			else if (time>sub_time)
			{
				sub_time =0;
				
			}
			else if ((sub_time -time) > 3)
			{
				sub_time =0;
				
			}

			ret = 1;
		}
		else if (subtitle->sub_task_control.command == MP_SUBTITLE_TASK_COMMAND_PAUSE)
		{
			if (ret)
			{
				subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_CONTROL_CLEAN_SCREEN, 0);
				ret = 0;
			}
		}

		osal_task_sleep(10);

	};

	subtitle->subtitle_osd_functions.osd_destroy(subtitle->subtitle_osd);

	osal_flag_set(subtitle->sub_task_control.parameter.flag_id, MP_SUBTITLE_FLAG_TASK_EXIT);
	
	MP_SUB_DEBUG("<<====mp_subtitle_task()\n");	
}

/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_image_task
//
// Description:
//	The task for output image subtitle. It will auto sync with current playing video
//
// Arguments:
//	param1 - Subtitle Handle
//	param2 - Not in use	
//
// Return Value:
//	None
//
/////////////////////////////////////////////////////////////////////////////
static void mp_subtitle_image_task(unsigned long param1,unsigned long param2)
{
	long								time;
	long								sub_time;
	MpSubtitle						*subtitle;
	long								ret;
	
	long									index;
	char									*filename;
	FILE									*file;
	char									file_path[FULL_PATH_SIZE+100];
	struct stat							file_status;
	char 								*ext;
	MpVobSubMpeg						mpeg;
	char									spu_fragment[2048];
	MpVobSubSpu							*spu;
	unsigned long							delay_time;
	unsigned long							start_time;	
	unsigned long							elapse_time;

	
	
	MP_SUB_DEBUG("====>>mp_subtitle_image_task()\n");

	sub_time = 0;
	delay_time = 0;
	start_time = 0;
	elapse_time = 0;
	subtitle = (MpSubtitle*)param1;

	index = subtitle->current_pos;
	if (index<0 || index>subtitle->total_sub_count-1)
	{
		index=0;
	}

	subtitle->current_pos = index;


	filename = subtitle->avail_sub_files[subtitle->current_sub_file_id].avail_sub_file;
	STRCPY(file_path, filename);
	ext = strrchr(file_path, (long)'.');
	if (!ext)
	{
		MP_SUB_DEBUG("mp_subtitle_image_task: Wrong Video File Name!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_image_task()\n");
		osal_flag_set(subtitle->sub_task_control.parameter.flag_id, MP_SUBTITLE_FLAG_UNSUCCESSFUL);
		return;
	}

	strncpy(ext, ".SUB", 4);
	ret = fs_stat(file_path, &file_status);
	if (ret < 0)
	{
		strlwr(ext);
		ret = fs_stat(file_path, &file_status);
	}
	
	if (ret < 0)
	{
		MP_SUB_DEBUG("mp_subtitle_image_task: Sub File is not existed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_image_task()\n");
		osal_flag_set(subtitle->sub_task_control.parameter.flag_id, MP_SUBTITLE_FLAG_UNSUCCESSFUL);
		return;
	}


	
	file = fopen(file_path, "rb");
	if (!file)
	{
		MP_SUB_DEBUG("mp_subtitle_image_task: Open file failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_image_task()\n");
		osal_flag_set(subtitle->sub_task_control.parameter.flag_id, MP_SUBTITLE_FLAG_UNSUCCESSFUL);
		return;
	}

	spu = (MpVobSubSpu*)MALLOC(sizeof(MpVobSubSpu));
	if (!spu)
	{
		fclose(file);
		MP_SUB_DEBUG("mp_subtitle_image_task: Malloc spu failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_image_task()\n");
		osal_flag_set(subtitle->sub_task_control.parameter.flag_id, MP_SUBTITLE_FLAG_UNSUCCESSFUL);
		return;
	}
	
	MEMSET(spu, 0, sizeof(MpVobSubSpu));
	
	FREE(subtitle->file_buffer);
	subtitle->file_buffer = NULL;
	subtitle->file_buffer_size_limit = 0;

	mpeg.packet_reserve = 2048;
	mpeg.packet = spu_fragment;
	

	
	ret = subtitle->subtitle_osd_functions.osd_create(&subtitle->subtitle_osd);
	if (ret < 0)
	{
		fclose(file);
		MP_SUB_DEBUG("mp_subtitle_image_task: Create osd failed!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_image_task()\n");
		osal_flag_set(subtitle->sub_task_control.parameter.flag_id, MP_SUBTITLE_FLAG_UNSUCCESSFUL);
		return;
	}

	subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_CHANGE_PALLETE, (long)subtitle->vob_sub.palette);

	osal_flag_set(subtitle->sub_task_control.parameter.flag_id, MP_SUBTITLE_FLAG_SUCCESS);


	while(subtitle->sub_task_control.command != MP_SUBTITLE_TASK_COMMAND_STOP)
	{
		
		if (subtitle->sub_task_control.command == MP_SUBTITLE_TASK_COMMAND_NONE)
		{
			time = subtitle->get_time();
			if (subtitle->time_in_ms)
			{
				time /= 100;
			}
			
			if (time <= 0)
			{
				osal_task_sleep(10);
				continue;
			}

			if (sub_time == 0)
			{
				if (subtitle->time_in_ms)
				{
					sub_time = mp_subtitle_get_sub(subtitle, time*100);
					sub_time /= 100;
				}
				else
				{
					sub_time = mp_subtitle_get_sub(subtitle, time*1000);
					sub_time /= 1000;
				}
			}	

			if (sub_time < 0)
			{
				osal_task_sleep(10);
				continue;
			}


			if (time == sub_time)
			{
				sub_time = 0;
				delay_time = 0;
				mp_subtitle_output_image1(subtitle, file, &file_status, file_path, &mpeg, spu, &delay_time);
				start_time = osal_get_tick();

			}
			else if (time>sub_time)
			{
				sub_time =0;
				
			}
			else if ((sub_time -time) > 3)
			{
				sub_time =0;
				
			}

			if (delay_time)
			{
				elapse_time = osal_get_tick() - start_time;
				if (elapse_time >= delay_time)
				{
					subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_CONTROL_CLEAN_SCREEN, 0);
					delay_time = 0;
				}
			}

			ret = 1;
		}
		else if (subtitle->sub_task_control.command == MP_SUBTITLE_TASK_COMMAND_PAUSE)
		{
			if (ret)
			{
				subtitle->subtitle_osd_functions.osd_control(subtitle->subtitle_osd, MP_SUBTITLE_CONTROL_CLEAN_SCREEN, 0);				
				ret = 0;
			}

			delay_time = 0;
		}

		osal_task_sleep(10);

	}

	if (spu->image)
	{
		FREE(spu->image);
		spu->image = NULL;
	}
	
	FREE(spu);
	
	fclose(file);

	subtitle->subtitle_osd_functions.osd_destroy(subtitle->subtitle_osd);

	osal_flag_set(subtitle->sub_task_control.parameter.flag_id, MP_SUBTITLE_FLAG_TASK_EXIT);
	
	MP_SUB_DEBUG("<<====mp_subtitle_task()\n");	
}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_start
//
// Description:
//	Start a subtitle task
//
// Arguments:
//	subtitle - Subtitle Handle
//	
// Return Value:
//	1 - Success
//	-1 - Failed
//
/////////////////////////////////////////////////////////////////////////////
static long mp_subtitle_start(MpSubtitle *subtitle)
{
	OSAL_T_CTSK										task_attribute;
	unsigned long											flag;
	
	MP_SUB_DEBUG("====>>mp_subtitle_start()\n");
	
	if ((!subtitle))
	{
		MP_SUB_DEBUG("mp_subtitle_start: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_start()\n");
		return -1;
	}


	if (subtitle->sub_task_control.status == MP_SUBTITLE_TASK_RUNNING)
	{
		MP_SUB_DEBUG("mp_subtitle_start: Task already running!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_start()\n");
		return -1;
	}


	subtitle->sub_task_control.command = MP_SUBTITLE_TASK_COMMAND_NONE;

	
	subtitle->sub_task_control.parameter.flag_id = OSAL_INVALID_ID;
	subtitle->sub_task_control.parameter.task_id = OSAL_INVALID_ID;

	//code to create flag
	flag = MP_SUBTITLE_FLAG_INITIALIZE;
	subtitle->sub_task_control.parameter.flag_id = osal_flag_create(flag);
	if ( subtitle->sub_task_control.parameter.flag_id == OSAL_INVALID_ID)
	{
		MP_SUB_DEBUG("mp_subtitle_start osal_flag_create failure! \n");
		MP_SUB_DEBUG("<<====mp_subtitle_start()\n");
		return -1;
	}


	//start thread
	task_attribute.stksz	= MP_SUBTITLE_PLAY_TASK_STACKSIZE;
	task_attribute.quantum	= MP_SUBTITLE_PLAY_TASK_QUANTUM;
	task_attribute.itskpri	= OSAL_PRI_NORMAL;
	task_attribute.para1	= (unsigned long)subtitle;
	//task_attribute.para2	=;
	task_attribute.name[0]	= 'S';
	task_attribute.name[1]	= 'u';
	task_attribute.name[2]	= 'b';
	if (subtitle->avail_sub_files[subtitle->current_sub_file_id].avail_file_type == MP_SUBTITLE_TYPE_SUB)
	{
		task_attribute.task = (FP)mp_subtitle_image_task;
	}
	else
	{
		task_attribute.task = (FP)mp_subtitle_txt_task;
	}
	subtitle->sub_task_control.parameter.task_id = osal_task_create(&task_attribute);
	if(subtitle->sub_task_control.parameter.task_id == OSAL_INVALID_ID)
	{
		osal_flag_delete(subtitle->sub_task_control.parameter.flag_id);
		subtitle->sub_task_control.parameter.flag_id = OSAL_INVALID_ID;
		MP_SUB_DEBUG("mp_subtitle_start osal_task_create failed! \n");
		MP_SUB_DEBUG("<<====mp_subtitle_start()\n");
		return -1;
	}
	
	//code to sync
	osal_flag_wait(&flag, subtitle->sub_task_control.parameter.flag_id, MP_SUBTITLE_FLAG_MASK, OSAL_TWF_ORW | OSAL_TWF_CLR, OSAL_WAIT_FOREVER_TIME);
	if (flag != MP_SUBTITLE_FLAG_SUCCESS)
	{		
		osal_flag_delete(subtitle->sub_task_control.parameter.flag_id);
		subtitle->sub_task_control.parameter.flag_id = OSAL_INVALID_ID;
		MP_SUB_DEBUG("mp_subtitle_start osal_task_create failed! \n");
		MP_SUB_DEBUG("<<====mp_subtitle_start\n");
		return -1;
	}


	subtitle->sub_task_control.status = MP_SUBTITLE_TASK_RUNNING;
	
	MP_SUB_DEBUG("<<====mp_subtitle_start\n");
	
	return 1;

}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_stop
//
// Description:
//	To stop subtitle task
//
// Arguments:
//	subtitle - Subtitle Handle
//
// Return Value:
//	None
//
/////////////////////////////////////////////////////////////////////////////
static void mp_subtitle_stop(MpSubtitle *subtitle)
{
	unsigned long									flag;
	
	MP_SUB_DEBUG("====>>mp_subtitle_stop()\n");
	
	if ((!subtitle))
	{
		MP_SUB_DEBUG("mp_subtitle_stop: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_stop()\n");
		return;
	}

	if (subtitle->sub_task_control.status == MP_SUBTITLE_TASK_STOPPED)
	{
		MP_SUB_DEBUG("mp_subtitle_stop: Task already stopped!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_stop()\n");
		return;
	}

	subtitle->sub_task_control.command = MP_SUBTITLE_TASK_COMMAND_STOP;
	osal_flag_wait(&flag, subtitle->sub_task_control.parameter.flag_id, MP_SUBTITLE_FLAG_MASK, OSAL_TWF_ORW | OSAL_TWF_CLR, OSAL_WAIT_FOREVER_TIME);
	
	subtitle->sub_task_control.parameter.task_id = OSAL_INVALID_ID;
	osal_flag_delete(subtitle->sub_task_control.parameter.flag_id);
	subtitle->sub_task_control.parameter.flag_id = OSAL_INVALID_ID;

	subtitle->sub_task_control.status = MP_SUBTITLE_TASK_STOPPED;

	mp_subtitle_callback = NULL;

	MP_SUB_DEBUG("<<====mp_subtitle_stop()\n");

}
/////////////////////////////////////////////////////////////////////////////
// mp_subtitle_pause
//
// Description:
//	To pause subtitle task
//
// Arguments:
//	subtitle - Subtitle Handle
//	pasued - Pause or Resume
//
// Return Value:
//	None
//
/////////////////////////////////////////////////////////////////////////////
static void mp_subtitle_pause(MpSubtitle *subtitle, long paused)
{
	MP_SUB_DEBUG("====>>mp_subtitle_pause()\n");
	
	if ((!subtitle))
	{
		MP_SUB_DEBUG("mp_subtitle_pause: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_pause()\n");
		return;
	}

	if (paused)
	{
		subtitle->sub_task_control.command = MP_SUBTITLE_TASK_COMMAND_PAUSE;
	}
	else
	{
		subtitle->sub_task_control.command = MP_SUBTITLE_TASK_COMMAND_NONE;
	}

	MP_SUB_DEBUG("<<====mp_subtitle_pause()\n");
}

static long mp_subtitle_io_ctrl(void *handle, long io_cmd, long param1, long param2)
{
       MpSubtitle						*subtitle;
	FILE								*file;
	char								*filename;
	char								*ext;
	long								type;
	long								ret;

	
	MP_SUB_DEBUG("====>>mp_subtitle_io_ctrl()\n");

	if (!handle)
	{
		MP_SUB_DEBUG("mp_subtitle_parse: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_io_ctrl()\n");
		return -1;
	}


	subtitle = (MpSubtitle*)handle;

	if ((subtitle->current_sub_file_id < 0) || (subtitle->avail_file_count > MP_SUBTITLE_TYPE_NUMBER))
	{
		MP_SUB_DEBUG("mp_subtitle_io_ctrl: Invalid Parameters!\n");
		MP_SUB_DEBUG("<<====mp_subtitle_io_ctrl()\n");
		return -1;
	}

	type = subtitle->avail_sub_files[subtitle->current_sub_file_id].avail_file_type;

	 switch(io_cmd)
        {
            case GET_SUBTITLE_FILE_SIZE:
			
		     	filename = subtitle->avail_sub_files[subtitle->current_sub_file_id].avail_sub_file;

			if(type ==  MP_SUBTITLE_TYPE_SUB) {
				ext = strrchr(filename, (long)'.');
				if (!ext)
				{
					return -1;
				}

				strncpy(ext, ".sub", 4);
				file = fopen(filename, "rb");
			} else {
				file = fopen(filename, "rb");
			}

			MP_SUB_DEBUG("the subtitle file name is: %s\n", filename);
			if (!file)
			{
				MP_SUB_DEBUG("mp_subtitle_io_ctrl: Open file failed!\n");
				MP_SUB_DEBUG("<<====mp_subtitle_io_ctrl()\n");
				return -1;
			}

			fseek(file, 0, SEEK_END);   
			ret = ftell(file);
			fseek(file, 0, SEEK_SET);
                	break;

		case GET_SUBTITLE_FILE_TIME:
			if(type ==  MP_SUBTITLE_TYPE_SUB) {
				ret =subtitle->position_time[subtitle->total_sub_count-1] ;
			} else {
				ret =subtitle->position_time[subtitle->total_sub_count-2] ;
			}
			MP_SUB_DEBUG("the subtitle count is: %d\n", subtitle->total_sub_count);
			break;
			
        case SET_SUBTITLE_STRING_TO_UNICODE:
            mp_lang_type = param1;
			mp_subtitle_callback = (mp_subtitle_string_to_unicode) param2;
			break;
            default:
				break;
				
	 }
	
    return ret;
}

#if (SYS_CHIP_MODULE == ALI_S3602 || SYS_CHIP_MODULE == ALI_M3329E)
const EXT_SUB_PLUGIN mp_subtitle_plugin __attribute__ ((section(".extsubt.plugin"))) =
{
	mp_subtitle_create,
	mp_subtitle_delete,
    mp_find_ext_subtitle,
	mp_subtitle_auto_load,
	mp_subtitle_unload,
	mp_subtitle_hide_sub,
	mp_subtitle_query_language,
	mp_subtitle_change_language,	
	mp_subtitle_load,
	mp_subtitle_io_ctrl,
	#if 1//joey.che 
	mp_subtile_get_sub_file_num,
	mp_subtile_get_cur_sub_id,
	mp_subtitle_change_ext_sub_id,
	#endif
};
#endif
